package com.siyoumi.util;

import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
//字符串工具类
public class XStr {
    /**
     * 前匹配
     */
    public static Boolean startsWith(String s, String start) {
        return StringUtils.startsWith(s, start);
    }

    /**
     * 后匹配
     */
    public static Boolean endsWith(String s, String end) {
        return StringUtils.endsWith(s, end);
    }

    /**
     * 前后匹配
     */
    public static Boolean contains(String s, String contains) {
        return StringUtils.contains(s, contains);
    }

    /**
     * 为空
     *
     * @return bool
     */
    public static Boolean isNullOrEmpty(String s) {
        if (StringUtils.isBlank(s)) {
            return true;
        }
        if (s.equals("null")) {
            return true;
        }
        return s.equals("undefined");
    }

    /**
     * 不为空
     *
     * @return bool
     */
    public static Boolean hasAnyText(String s) {
        return !isNullOrEmpty(s);
    }

    /**
     * 字符串转换成日期
     *
     * @param yyyyMMddhhmmss 日期字符串
     */
    public static LocalDateTime toDateTime(String yyyyMMddhhmmss) {
        if (isNullOrEmpty(yyyyMMddhhmmss)) {
            return null;
        }

        return XDate.parse(yyyyMMddhhmmss);
    }


    public static Integer toInt(String str, Integer def) {
        if (XStr.isNullOrEmpty(str)) {
            return def;
        }
        return parseType(str, Integer.class, def);
    }

    public static Integer toInt(String str) {
        return toInt(str, 0);
    }

    public static Long toLong(String str) {
        return parseType(str, Long.class, 0L);
    }

    public static BigDecimal toBigDecimal(Object str) {
        if (str == null) {
            return new BigDecimal("0");
        }
        return parseType(str.toString(), BigDecimal.class, 0);
    }

    public static <T> T parseType(String str, Class<T> type, Object def) {
        if (str == null) {
            return (T) def;
        }

        Object v = def;
        try {
            if (type == LocalDateTime.class) {
                v = XStr.toDateTime(str);
            } else if (type == Integer.class) {
                v = Integer.parseInt(str);
            } else if (type == Long.class) {
                v = Long.parseLong(str);
            } else if (type == BigDecimal.class) {
                v = new BigDecimal(str);
            } else if (type == String.class) {
                v = str;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return (T) v;
    }


    /**
     * 下划线转驼峰
     */
    public static String lineToHump(String str) {
        Pattern UNDERLINE_PATTERN = Pattern.compile("_([a-z])");

        str = str.toLowerCase();
        Matcher matcher = UNDERLINE_PATTERN.matcher(str);
        StringBuilder sb = new StringBuilder();
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }


    /**
     * 根据map替换
     */
    public static String replaceByMap(String str, Map<String, String> map) {
        for (Map.Entry<String, String> entry : map.entrySet()) {
            str = str.replace(entry.getKey(), entry.getValue());
        }

        return str;
    }


    /**
     * 首字母大写
     */
    public static String toUpperCase1(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }


    /**
     * 对象转json字符串
     *
     * @param s
     */
    public static String toJsonStr(Object s) {
        return XJson.toJSONString(s);
    }

    public static Map toJson(String s) {
        if (isNullOrEmpty(s)) {
            return new HashMap<String, Object>();
        }


        return XJson.parseObject(s, Map.class);
    }

    public static List<Map> toJsonArr(String s) {
        if (isNullOrEmpty(s)) {
            return null;
        }

        return XJson.parseArray(s, Map.class);
    }


    /**
     * md5 加密
     */
    public static String md5(String s) {
        return DigestUtils.md5Hex(s);
    }

    /**
     * md5 加密
     */
    public static String sha256(String s) {
        return DigestUtils.sha256Hex(s);
    }

    /**
     * hmacSHA256加密
     *
     * @param s   需要加密字符串
     * @param key 密钥
     */
    public static byte[] hmacSHA256(String s, String key) {
        byte[] sign = new byte[0];
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
            sign = mac.doFinal(s.getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return sign;
    }

    /**
     * base64解密
     */
    public static String base64Dec(String str) {
        String new_str = "";
        try {
            new_str = new String(Base64.getDecoder().decode(str.getBytes()));
        } catch (Exception ex) {
        }
        return new_str;
    }

    /**
     * base64加密
     */
    public static String base64Enc(String str) {
        return base64Enc(str.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * base64加密
     */
    public static String base64Enc(byte[] str) {
        return Base64.getEncoder().encodeToString(str);
    }


    public static String urlEnc(String str) {
        return URLEncoder.encode(str, StandardCharsets.UTF_8);
    }

    public static String urlDec(String str) {
        return URLDecoder.decode(str, StandardCharsets.UTF_8);
    }

    /**
     * 获取url?后面的参数
     *
     * @param url
     */
    public static Map<String, String> urlQuery(String url) {
        String query = "";
        try {
            URL urlObj = new URL(url);
            query = urlObj.getQuery();
        } catch (Exception ex) {
            ex.printStackTrace();
            log.error(ex.getMessage());
        }

        if (isNullOrEmpty(query)) {
            return new HashMap<>();
        }

        Map<String, String> mapKeyVal = new HashMap<>();

        String[] queryArr = query.split("&");
        for (String item : queryArr) {
            String[] keyVal = item.split("=", 2);
            mapKeyVal.put(keyVal[0], keyVal[1]);
        }
        return mapKeyVal;
    }

    /**
     * 拼接字符串
     *
     * @param strs
     */
    public static String concat(String... strs) {
        StringBuilder sb = new StringBuilder();
        for (String s : strs) {
            sb.append(s);
        }

        return sb.toString();
    }

    /**
     * 拼接字符串
     *
     * @param s
     * @param args 格式：{0}、{1}
     */
    public static String format(String s, String... args) {
        if (XStr.isNullOrEmpty(s)) {
            return s;
        }

        if (args.length <= 0) {
            return s;
        }

        for (int i = 0; i < args.length; i++) {
            String val = args[i];
            if (val == null) {
                val = "null";
            }

            s = s.replace("{" + i + "}", val);
        }
        return s;
    }

    /**
     * 数组转key=val
     *
     * @param excludeKeys 过滤key
     * @param doUrlEncode true:urlencode
     * @return 返回key=val&key2=val2
     */
    public static String queryFromMap(@NonNull Map<String, String> map, List<String> excludeKeys, Boolean doUrlEncode) {
        if (map.isEmpty()) {
            return "";
        }

        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            String key = entry.getKey();
            if (excludeKeys != null) {
                if (excludeKeys.contains(key)) {
                    continue;
                }
            }

            String val = entry.getValue();
            if (doUrlEncode) {
                val = XStr.urlEnc(val);
            }

            String item = XStr.concat("&", key, "=", val);
            sb.append(item);
        }

        return sb.substring(1);
    }

    /**
     * 获取字符串最大长度
     *
     * @param s   原字符串
     * @param max 截取长度
     * @return 字符串
     */
    public static String maxLen(String s, Integer max) {
        int len = s.length();
        if (len < max) {
            return s;
        }

        return s.substring(0, max);
    }


    /**
     * 截取（字节）
     *
     * @param s
     * @param max          截取长度（字节，1个汉字=4）
     * @param maxAppendStr 超出长度后面追加字符
     */
    public static String maxLenByte(String s, int max, String maxAppendStr) {
        if (isNullOrEmpty(s)) {
            return s;
        }

        byte[] bytes = s.getBytes();
        if (bytes.length <= max) {
            return s;
        }

        int byteLen = new String(bytes, 0, max).length();
        s = s.substring(0, byteLen);
        // 防止最后一个字符的长度不是一个字节数
        if (s.getBytes().length > max) {
            s = s.substring(0, byteLen - 1);
        }
        if (hasAnyText(maxAppendStr)) {
            //超出长度后面加...
            s += maxAppendStr;
        }

        return s;
    }


    public static String substring(String s, int begin, int end) {
        int len = end - begin;
        if (s.length() <= len) {
            return s;
        }

        return s.substring(begin, end);
    }


    /**
     * 正则表达式，是否匹配到
     *
     * @param s
     * @param reg
     */
    public static Boolean matches(String s, String reg) {
        Pattern p = Pattern.compile(reg);
        Matcher matcher = p.matcher(s);

        return matcher.matches();
    }

    /**
     * 字条串是否存在
     *
     * @param arr
     * @param search
     */
    public static boolean exists(String[] arr, String search) {
        for (String s : arr) {
            if (search.equals(s)) {
                return true;
            }
        }

        return false;
    }

    public static String toString(byte[] bytes, Charset charset) {
        return new String(bytes, charset);
    }

    public static String toString(byte[] bytes) {
        return toString(bytes, StandardCharsets.UTF_8);
    }

    public static byte[] toByte(String s) {
        return toByte(s, StandardCharsets.UTF_8);
    }

    public static byte[] toByte(String s, Charset charset) {
        return s.getBytes(charset);
    }


    static public String markStarPhone(String s) {
        return markStar(s, 3, 4);
    }

    /**
     * 字段加星
     * 18819208821 前3，后4
     * 188****8821
     *
     * @param s
     * @param keepBeginLen 保留前多少个字符
     * @param keepEndLen   保留后多少个字符
     */
    static public String markStar(String s, int keepBeginLen, int keepEndLen) {
        if (isNullOrEmpty(s)) {
            return s;
        }
        if (s.length() <= (keepBeginLen + keepEndLen)) {
            return s;
        }

        int starLen = s.length() - (keepBeginLen + keepEndLen);


        StringBuilder sb = new StringBuilder();
        sb.append(s, 0, keepBeginLen);
        for (int i = 0; i < starLen; i++) {
            sb.append("*");
        }
        sb.append(s, keepBeginLen + starLen, s.length());
        return sb.toString();
    }


    static public List<String> arrToList(String[] arr) {
        List<String> list = new ArrayList<>();
        if (arr == null) {
            return list;
        }

        for (String s : arr) {
            list.add(s);
        }
        return list;
    }

    static public String[] listToArr(List<String> list) {
        return list.toArray(new String[0]);
    }
}
